﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Quartz;
using System;
using System.Collections.Generic;
using System.IO;
using System.Data.Objects;
using System.Linq;
using System.Xml.Linq;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.Collections.Generic;
using System.Collections;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using DevExpress.Data.Filtering;
using System.Security.Authentication;
using System.Web.Security;
using System.Web.ClientServices.Providers;
using System.Configuration;
using System.Collections;
using System.Web;
using Coevery.Services.Metadata;
using System.Data.Entity;
using System.Linq.Expressions;
using System.Collections.Generic;

using System.Data.Entity;


namespace Coevery.Services.Tasacion
{
    public class TasacionJob : IJob
    {

        CoeveryEntities _context; // Acceder directamente a metadatas
        MetadataService _service; // Acceder a metodos que ya encapsulan logica con linq/metadatas

        private CoeveryEntities _getCoeveryEntities()
        {
            if (_context == null)
                _context = CoeveryEntities.CreateInstance();
            return _context;
        }


        public void Execute(IJobExecutionContext context)
        {
            Console.WriteLine("Tarea de tasacion en background");
            Tasar();
        }

        public void Execute() // Replica de Metodo para las pruebas
        {
            Console.WriteLine("Tarea de tasacion en background");
        }

        private void Tasar()
        {
            // 1. Encontrar pisos no tasados (TasacionId a nulo)

            // 2. Encontrar pisos cercanos y guardarlos en BBDD

            // 3. Encontrar información de catastro y guardarlo en BBDD

            // 4. Determinar precio (logica de motor)

            // 5. Generar PDF

            // TEST GUARDAR EN BBDD una FOTO

            
            var filterEntiy = _getCoeveryEntities().Entities.Where(c => c.EntityId == new Guid("F2B59D2F-B244-4776-94CC-12A9D63A898C")).First(); // Foto.EntityId
            
            DbContext commonContext = DynamicModelBuilder.CreateDataSource();
            
            //FilterCriteriaHelper helper = new FilterCriteriaHelper(oldValue, entityTypeId);
            //CriteriaOperator theOperator = helper.GeneratrCriteria(config.Criterion);

            Type filterEntityType2 = DynamicTypeBuilder.Instance.GetDynamicType(filterEntiy.Name);
           
            IQueryable query = commonContext.Set(filterEntityType2).AsQueryable();
            try
            {
                System.Linq.Expressions.Expression expression = GetExpression(query,
                    CriteriaOperator.Parse("IsNull([TasacionId])"));
                query = query.Provider.CreateQuery(expression);
                IEnumerator iter = query.GetEnumerator();
                var tempEntityList = new ArrayList();
                while (iter.MoveNext())
                {
                    tempEntityList.Add(iter.Current);
                }

                GetAndSavePisosCercanos(commonContext, tempEntityList); 
            }
            catch
            {

            }
        }


        private void GetAndSavePisosCercanos(DbContext commonContext,  ArrayList tempEntityList)
        {

            var filterEntiy = _getCoeveryEntities().Entities.Where(c => c.EntityId == new Guid("F2B59D2F-B244-4776-94CC-12A9D63A898C")).First(); // Foto.EntityId
            Type filterEntityType = DynamicTypeBuilder.Instance.GetDynamicType(filterEntiy.Name);
            
            foreach (Object inm in tempEntityList){

                try
                {

                    // Como actualizo el TasacionId de un piso que voy a tasar?????

                    Guid nuevaTasacionId = Guid.NewGuid();
                    Guid inmuebleId = (Guid)GetPropertyValue(inm, "InmuebleId");
                    var recipientInfo = Activator.CreateInstance(DynamicTypeBuilder.Instance.GetDynamicType("Inmueble"));
                    
                    Object inmueble = commonContext.Set(filterEntityType).Find(inmuebleId);          

                    Guid id = (Guid)GetPropertyValue(inm, "InmuebleId");
                    String lat = (String)GetPropertyValue(inm, "Latitud");
                    String lon = (String)GetPropertyValue(inm, "Longitud");

                    JsonData respuesta = TasacionDataHelper.buscarInmueblesProximos(lat, lon, null);
                    if (respuesta.elementList.Count() > 0)
                        SetPropertyValue(inm, "TasacionId", nuevaTasacionId);
                    foreach (Element jsonInm in respuesta.elementList)
                    {

                        var inmuebleIdealistaEntity = _getCoeveryEntities().Entities.Where(c => c.EntityId == new Guid("432DA8D2-E0A6-4D2E-A25B-C96D88373B16")).First(); // InmuebleIdealista
                        Type inmuebleIdealistaType = DynamicTypeBuilder.Instance.GetDynamicType(inmuebleIdealistaEntity.PhysicalName);
                        var inmuebleIdealistaInstance = Activator.CreateInstance(DynamicTypeBuilder.Instance.GetDynamicType(inmuebleIdealistaType.Name));


                        Guid InmuebleIdealistaId = Guid.NewGuid();
                        SetPropertyValue(inmuebleIdealistaInstance, "InmuebleIdealistaId", InmuebleIdealistaId);
                        SetPropertyValue(inmuebleIdealistaInstance, "InmuebleId", id);

                        SetPropertyValue(inmuebleIdealistaInstance, "AbrAddress", jsonInm.abrAddress);
                        SetPropertyValue(inmuebleIdealistaInstance, "Address", jsonInm.address);
                        SetPropertyValue(inmuebleIdealistaInstance, "Agency", jsonInm.agency);
                        SetPropertyValue(inmuebleIdealistaInstance, "AgentLogo", jsonInm.agentLogo);
                        SetPropertyValue(inmuebleIdealistaInstance, "Bathrooms", jsonInm.bathrooms);
                        SetPropertyValue(inmuebleIdealistaInstance, "Condition", jsonInm.condition);
                        SetPropertyValue(inmuebleIdealistaInstance, "Country", jsonInm.country);
                        SetPropertyValue(inmuebleIdealistaInstance, "Description", jsonInm.description);
                        SetPropertyValue(inmuebleIdealistaInstance, "Distance", jsonInm.distance);
                        SetPropertyValue(inmuebleIdealistaInstance, "District", jsonInm.district);
                        SetPropertyValue(inmuebleIdealistaInstance, "FavComment", jsonInm.favComment);
                        SetPropertyValue(inmuebleIdealistaInstance, "Favourite", jsonInm.favourite);
                        SetPropertyValue(inmuebleIdealistaInstance, "Floor", jsonInm.floor);
                        SetPropertyValue(inmuebleIdealistaInstance, "HasVideo", jsonInm.hasVideo);
                        SetPropertyValue(inmuebleIdealistaInstance, "Latitude", jsonInm.latitude);
                        SetPropertyValue(inmuebleIdealistaInstance, "Longitude", jsonInm.longitude);
                        SetPropertyValue(inmuebleIdealistaInstance, "Munipality", jsonInm.munipality);
                        SetPropertyValue(inmuebleIdealistaInstance, "Neighborhood", jsonInm.neighborhood);
                        SetPropertyValue(inmuebleIdealistaInstance, "NumPhotos", jsonInm.numPhotos);
                        SetPropertyValue(inmuebleIdealistaInstance, "Operation", jsonInm.operation);
                        SetPropertyValue(inmuebleIdealistaInstance, "PhotosUrl", jsonInm.photosUrl);
                        SetPropertyValue(inmuebleIdealistaInstance, "Position", jsonInm.position);
                        SetPropertyValue(inmuebleIdealistaInstance, "Price", jsonInm.price);
                        SetPropertyValue(inmuebleIdealistaInstance, "PropertyCode", jsonInm.propertyCode);
                        SetPropertyValue(inmuebleIdealistaInstance, "PropertyType", jsonInm.propertyType);
                        SetPropertyValue(inmuebleIdealistaInstance, "PropertyTypeCode", jsonInm.propertyTypeCode);
                        SetPropertyValue(inmuebleIdealistaInstance, "Province", jsonInm.province);
                        SetPropertyValue(inmuebleIdealistaInstance, "Region", jsonInm.region);
                        SetPropertyValue(inmuebleIdealistaInstance, "Rooms", jsonInm.rooms);
                        SetPropertyValue(inmuebleIdealistaInstance, "ShowAddress", jsonInm.showAddress);
                        SetPropertyValue(inmuebleIdealistaInstance, "Size", jsonInm.size);
                        SetPropertyValue(inmuebleIdealistaInstance, "Subregion", jsonInm.subregion);
                        SetPropertyValue(inmuebleIdealistaInstance, "Thumbnail", jsonInm.thumbnail);
                        SetPropertyValue(inmuebleIdealistaInstance, "TipUsuCd", jsonInm.tipUsuCd);
                        SetPropertyValue(inmuebleIdealistaInstance, "Url", jsonInm.url);
                        SetPropertyValue(inmuebleIdealistaInstance, "UserCode", jsonInm.userCode);
                        SetPropertyValue(inmuebleIdealistaInstance, "VideoType", jsonInm.videoType);
                        if ((jsonInm.propertyCode == null) || (jsonInm.propertyCode == ""))
                            jsonInm.propertyCode = TasacionDataHelper.obtenerProperyCode(jsonInm);
                        SetPropertyValue(inmuebleIdealistaInstance, "PropertyCode", jsonInm.propertyCode);

                        List<byte[]> fotos = TasacionDataHelper.obtenerFotos(jsonInm.propertyCode);

                        foreach (var foto in fotos){
                            try
                            {
                                Type fotoType = DynamicTypeBuilder.Instance.GetDynamicType("Foto");
                                var fotoInstance = Activator.CreateInstance(DynamicTypeBuilder.Instance.GetDynamicType(fotoType.Name));

                                SetPropertyValue(fotoInstance, "FotoId", Guid.NewGuid());
                                SetPropertyValue(fotoInstance, "InmuebleId", InmuebleIdealistaId);
                                SetPropertyValue(fotoInstance, "Img", foto);

                                commonContext.Set(fotoType).Add(fotoInstance);
                                commonContext.SaveChanges();
                            }
                            catch (Exception e) {
                                Debug.WriteLine("Mirar SQL SERVER PROFILER...");
                            }

                        }

                        //commonContext.Entry(inmuebleIdealistaInstance).State = System.Data.EntityState.Modified; //Esto no es una puta modificacion, es una insercion
                        commonContext.Set(inmuebleIdealistaType).Add(inmuebleIdealistaInstance);
                        commonContext.SaveChanges();
                        
                    }

                }
                catch {
                    Debug.WriteLine("Mirar SQL SERVER PROFILER...");
                }
              
            }
            
        }

        private void GetInformacionCatastro()
        {

            // Inmuebles propios
            var filterEntiy = _getCoeveryEntities().Entities.Where(c => c.EntityId == new Guid("F2B59D2F-B244-4776-94CC-12A9D63A898C")).First(); // Foto.EntityId

            DbContext commonContext = DynamicModelBuilder.CreateDataSource();

            Type filterEntityType2 = DynamicTypeBuilder.Instance.GetDynamicType(filterEntiy.Name);

            IQueryable query = commonContext.Set(filterEntityType2).AsQueryable();
            try
            {
                System.Linq.Expressions.Expression expression = GetExpression(query,
                    CriteriaOperator.Parse("IsNull([TasacionId])"));
                query = query.Provider.CreateQuery(expression);
                IEnumerator iter = query.GetEnumerator();
                var tempEntityList = new ArrayList();
                while (iter.MoveNext())
                {
                    tempEntityList.Add(iter.Current);
                }

                GetAndSavePisosCercanos(commonContext, tempEntityList);
            }
            catch
            {

            }
        }

        private void updateObjectSample()
        {
            // Ejemplo actualizacion objeto de dominio
            DbContext commonContext = DynamicModelBuilder.CreateDataSource();
            var filterEntiy = _getCoeveryEntities().Entities.Where(c => c.EntityId == new Guid("F2B59D2F-B244-4776-94CC-12A9D63A898C")).First(); // Foto.EntityId
            Type filterEntityType = DynamicTypeBuilder.Instance.GetDynamicType(filterEntiy.Name);
            Object  inmueble = commonContext.Set(filterEntityType).Find(new Guid("4A717823-49B3-4DDB-A216-095C83E82D8A"));
            commonContext.Entry(inmueble).State = System.Data.EntityState.Modified; 
            commonContext.SaveChanges();
        }

        private void createObjectSample()
        {

            // Ejemplo creacion objeto de dominio
            DbContext commonContext = DynamicModelBuilder.CreateDataSource();
            var filterEntiy2 = _getCoeveryEntities().Entities.Where(c => c.EntityId == new Guid("15721970-9EC0-4E18-8271-08F173DD64C3")).First(); // Foto.EntityId
            Type filterEntityType = DynamicTypeBuilder.Instance.GetDynamicType(filterEntiy2.Name);
            var recipientInfo = Activator.CreateInstance(filterEntityType);
            SetPropertyValue(recipientInfo, "PhotoId", Guid.NewGuid());
            SetPropertyValue(recipientInfo, "InmuebleId", new Guid("4A717823-49B3-4DDB-A216-095C83E82D8A"));
            SetPropertyValue(recipientInfo, "FotoDesc", "Foto de Test");
            SetPropertyValue(recipientInfo, "Img", new byte[256]);
            commonContext.Set(filterEntityType).Add(recipientInfo);
            commonContext.SaveChanges();
        }

        private List<Guid> GetUserList(NotificationProfile config, Dictionary<string, object> variablesValues, Guid operatorUserId)
        {
            DbContext commonContext = DynamicModelBuilder.CreateDataSource();
            List<Guid> userList = new List<Guid>();
            List<NotificationRecipientAttribute> recipientConfigs = config.NotificationRecipientAttributes.ToList() as List<NotificationRecipientAttribute>;
            MetadataService client = new MetadataService();
            GroupOperator theOperator = new GroupOperator();

            CriteriaOperator criteria = new BinaryOperator("Age", 30, BinaryOperatorType.Greater);


            var filterEntiy = _context.Entities.Where(c => c.EntityId == new Guid("")).First();
            Type filterEntityType = DynamicTypeBuilder.Instance.GetDynamicType(filterEntiy.Name);

            IQueryable query = commonContext.Set(filterEntityType).AsQueryable();
            System.Linq.Expressions.Expression exception = GetExpression(query, theOperator);
            query = query.Provider.CreateQuery(exception);
            IEnumerator iter = query.GetEnumerator();


            if (config.Subscriptions != null)
            {
                foreach (var subscription in config.Subscriptions)
                {
                    if (subscription.UserId != null && subscription.UserId != operatorUserId)
                        if (!userList.Contains((Guid)subscription.UserId)) userList.Add((Guid)subscription.UserId);
                }
            }
            commonContext.SaveChanges();

            return userList;
        }

        private static System.Linq.Expressions.Expression GetExpression(IQueryable query, CriteriaOperator theOperator)
        {
            var elementType = query.ElementType;
            var converter = new DevExpress.Data.Linq.CriteriaToExpressionConverter();
            ParameterExpression thisExpression = Expression.Parameter(elementType, "");
            Expression predicate =
                Expression.Quote(Expression.Lambda(converter.Convert(thisExpression, theOperator), thisExpression));

            MethodCallExpression methodCallExpression =
                Expression.Call(typeof(Queryable), "Where",
                                new Type[1] { elementType }, new Expression[2]
                                                                       {
                                                                           query.Expression, predicate
                                                                       });
            return methodCallExpression;
        }

        private static void SetPropertyValue(object obj, string propertyName, object value)
        {
            System.Reflection.PropertyInfo info = obj.GetType().GetProperty(propertyName);
            if (info == null) return;
            info.SetValue(obj, value, null);
        }

        private static object GetPropertyValue(object obj, string propertyName)
        {
            System.Reflection.PropertyInfo info = obj.GetType().GetProperty(propertyName);
            if (info == null) return null;
            return info.GetValue(obj, null);
        }
    }



}